OCMock 3
Creating mock objects
Class mocks
1 | id classMock = OCMClassMock([SomeClass class]); |
Protocol mocks
1 | id protocolMock = OCMProtocolMock(@protocol(SomeProtocol)); |
Strict class and protocol mocks
1 | id classMock = OCMStrictClassMock([SomeClass class]); |
Partial mocks
1 | id partialMock = OCMPartialMock(anObject); |
Creates a mock object that can be used in the same way as anObject. Any method that is not stubbed is forwarded to anObject. When a method is stubbed and that method is invoked using a reference to the real object, the mock will still be able to handle the invocation
Observer mocks
1 | id observerMock = OCMObserverMock(); |
Creates a mock object that can be used to observe notifications. The mock must be registered in order to receive notifications.
Stubbing methods
Stubbing methods that return objects
1 | OCMStub([mock someMethod]).andReturn(anObject); |
Tells the mock object that when someMethod is called it should return anObject.
Stubbing methods that return values
1 | OCMStub([mock aMethodReturningABoolean]).andReturn(YES); |
For methods that return primitive values it is important to use the right type of value. If, for example, a method returns a longbut the stub uses an int an error will occur. The message will include the expected and the actual type (using Objective-C type codes such as “q” for long and “i” for int).
Delegating to another method
1 | OCMStub([mock someMethod]).andCall(anotherObject, @selector(aDifferentMethod)); |
In this case the mock object will call aDifferentMethod on anotherObject when someMethod is called. The signature of the replacement method must be the same as that of the method that is replaced. Arguments will be passed, and the return value of the replacement method is returned from the stubbed method. It is common to implement the replacement method in the test case itself.
Delegating to a block
1 | OCMStub([mock someMethod]).andDo(^(NSInvocation *invocation) |
Returning values in pass-by-reference arguments
1 | OCMStub([mock someMethodWithReferenceArgument:[OCMArg setTo:anObject]]); |
The mock object will set the reference that is passed to the method to anObject and aValue. Use setTo: for pass-by-reference arguments that return objects and setToValue: and OCMOCK_VALUE() for arguments that return primitives.
Invoking block arguments
1 | OCMStub([mock someMethodWithBlock:[OCMArg invokeBlock]]); |
The mock object will invoke the block passed as an argument to the stubbed method. If the block takes arguments and invokeBlock is used, the default values for the argument types are used, e.g. zero for a numerical type. Using invokeBlockWithArgs: it is possible to specify which arguments to invoke the block with; non-object arguments must be wrapped in value objects and the expression must be wrapped in round brackets.
Throwing exceptions
1 | OCMStub([mock someMethod]).andThrow(anException); |
When someMethod is invoked the stub will throw anException.
Posting notifications
1 | OCMStub([mock someMethod]).andPost(aNotification); |
When someMethod is invoked the stub will post aNotification.
Chaining stub actions
1 | OCMStub([mock someMethod]).andPost(aNotification).andReturn(aValue); |
All actions such as andReturn and andPost can be chained. In this example the mock object will post a notification and return the value.
Forwarding to the real object / class
1 | OCMStub([mock someMethod]).andForwardToRealObject(); |
When using a partial mock and when mocking class methods it is possible to stub a method and forward it to the real object (in case of partial mocks) or to the class (when mocking class methods). This is only useful when chaining actions or when using expectations.
Doing nothing
1 | OCMStub([mock someMethod]).andDo(nil); |
It is possible to pass nil instead of a block to andDo. This is only useful with partial mocks or when mocking class methods. In these cases using andDo(nil) effectively suppresses the behaviour in the existing class.
Verifying interactions
Verify-after-running
1 | id mock = OCMClassMock([SomeClass class]); |
Verifies that someMethod has been called by the code under test. If the method has not been invoked an error is reported. In Xcode and AppCode the error is reported on the line of the verify, for other test environments an exception is thrown.
It is possible to use argument constraints in the verify statement.
Stubs and verification
1 | id mock = OCMClassMock([SomeClass class]); |
It is possible to stub a method and still verify that it has been called.
Argument constraints
The any constraint
1 | OCMStub([mock someMethodWithAnArgument:[OCMArg any]]) |
Adds a stub for the methods which is active for all invocations, no matter what argument is passed. Pointers and selectors require special treatment as shown above. Arguments that are neither objects nor pointers or selectors cannot be ignored using an any placeholder (for details see this forum thread). See just below for a workaround.
Ignoring non-object arguments
1 | [[[mock stub] ignoringNonObjectArgs] someMethodWithIntArgument:0] |
This tells the mock to ignore all non-object arguments in the invocation. It will accept any invocation of someMethodWithIntArgument: no matter what argument is actually passed. If the method has object arguments as well as non-object arguments, the object arguments can still be constrained as usual using the methods on OCMArg.
NOTE: this should have a modern syntax.
Matching arguments
1 | OCMStub([mock someMethod:aValue) |
If an argument is passed when the stub is created, the stub only matches invocations with that exact argument. Calls with different arguments are not matched. The OCMArg class provides several methods that allow matching values in different ways.
For checkWithSelector:onObject:, when the mock object receives someMethod:, it invokes aSelector on anObject. If the method takes an argument the mock will pass the argument that was passed to someMethod:. The method should return a boolean indicating whether the argument matched the expectation or not.
Using Hamcrest matchers
1 | OCMStub([mock someMethod:startsWith(@"foo")]) |
It is also possible to use Hamcrest matchers. This will only work when the Hamcrest framework is explicitly linked by the unit test bundle. OCMock does not declare a dependency on Hamcrest and discovers it using runtime functions.
Mocking class methods
Stubbing class methods
1 | id classMock = OCMClassMock([SomeClass class]); |
Stubs for class methods are set up exactly like stubs for instance methods. However, behind the scenes the mock object makes some changes to the class. (It dynamically creates a new meta class and makes the class use that instead of its own meta class.) This allows OCMock to stub calls which are made directly to the class.
IMPORTANT: If the mock object that added a stubbed class method is not deallocated then the stubbed method will persist across tests. If multiple mock objects manipulate the same class at the same time the behaviour is undefined.
Verifying invocations of class methods
1 | id classMock = OCMClassMock([SomeClass class]); |
Verification is done in the same way as with instance methods. As described above, calls can be made directly to the class.
Disambiguating class and instance methods
1 | id classMock = OCMClassMock([SomeClass class]); |
In cases where a class method should be stubbed but the class also has an instance method with the same name as the class method, as assumed with ambiguousMethod above, the intent to mock the class method must be made explicit using ClassMethod().
Restoring the class
1 | id classMock = OCMClassMock([SomeClass class]); |
The class can be returned to its original state by calling stopMocking. This is only necessary if the original state must be restored before the end of the test. The mock automatically calls stopMocking during its own deallocation.
When the class is returned to its original state, its meta class will be switched back to the original meta class. This effectively removes all the stubs. However, this also makes it impossible for the mock to add new stubs or to verify interactions. You should really not use a mock after having called stopMocking.
Partial mocks
Stubbing methods
1 | id partialMock = OCMPartialMock(anObject); |
From an API perspective stubs on partial mocks are set up in the same way as on class and protocol mocks. Partial mocks alter the class of the mocked object, though. (In fact, they create a subclass and switch the class of the mocked object to that subclass.) This means that calls using a reference to the real object, even including self in methods where the object calls itself, are also affected by stubs and expectations.
Verifying invocations
1 | id partialMock = OCMPartialMock(anObject); |
Verification is done in the same way as with class and protocol mocks. As described just above, calls using a reference to the real object are intercepted, too. There is no need to insure that a reference to the mock is used, calls can be made using references to the real object.
Restoring the object
1 | id partialMock = OCMPartialMock(anObject); |
The real object can be returned to its original state by calling stopMocking. This is only necessary if the original state must be restored before the end of the test. The partial mock automatically calls stopMocking during its own deallocation.
When the object is returned to its original state, its class will be switched back to the original class. This effectively removes all the stubs. However, this also makes it impossible for the partial mock to add new stubs or to verify interactions. You should really not use a partial mock after having called stopMocking.
Strict mocks and expectations
Expect-run-verify
1 | id classMock = OCMClassMock([SomeClass class]); |
This is the original approach to mocking. First the mock object is set up with expectations, then the code under test is run, and afterwards the expectations are verified. If an expected method has not been invoked, or has not been invoked with the right arguments, then an error is reported. As shown it is possible to use argument constraints in the expect statement. Strict mocks can be created for classes and protocols.
If in doubt use the newer verify-after-running approach described in Verifying interactions.
Strict mocks and failing fast
1 | id classMock = OCMStrictClassMock([SomeClass class]); |
The mock has been set up as a strict mock without any expectations. Calling someMethod will cause the mock to throw an exception. This is also known as failing fast because the test fails immediatly when the unexpected call is made. Only strict mocks fail fast.
Stub actions and expect
1 | id classMock = OCMStrictClassMock([SomeClass class]); |
It is possible to use andReturn, andThrow, etc with expectations, too. This will then run the stub action if and when the method is invoked and, on verify, ensure that the method was actually invoked.
Verify with delay
1 | id mock = OCMStrictClassMock([SomeClass class]); |
In certain cases the expected method will only be called when the run loop is active. For these cases it is possible to delay the verification for a while. Note that aDelay (expressed as NSTimeInterval) is the maximum the mock will wait. It normally returns as soon as the expectations have been met.
Verifying in order
1 | id mock = OCMStrictClassMock([SomeClass class]); |
The mock can be told to verify that expected methods are called in the same order as the expectations are set up. As soon as a method is called that is not next on the “expected list” the mock will fail fast and throw an exception.
Observer mocks
Setup
1 | id observerMock = OCMObserverMock(); |
Creates a mock object that can be used to observe notifications, registers it with a notification center, and tells the mock to expect SomeNotification with any object.
Verification
1 | OCMVerifyAll(observerMock); |
Currently observer mocks are always strict, they will raise an exception when an unexpected notification is received. This implies that individual notifications cannot be verified after the fact. All notifications must be set up with expect, and they are verified together after the code under test has run using OCMVerifyAll.
Advanced topics
Failing fast for regular (nice) mocks
On a strict mock object, when a method is called that has not been mocked (using some variant of stub or expect) the mock object will raise an exception. It will fail fast. Regular mock objects simply return the default value for the return type. Regular mocks can be configured on a per-method basis to fail fast:
1 | id mock = OCMClassMock([SomeClass class]); |
In this case the mock will accept all methods except someMethod; if that is invoked the mock will throw an exception.
Re-throwing fail fast exceptions in verify all
In fail-fast mode an exception might not cause the test to fail. This can happen when the call stack for the method does not end in the test. Fail fast exceptions will be re-thrown when OCMVerifyAll is called. This makes it possible to ensure that unwanted invocations from notifications etc. can be detected.
Stubbing methods that create objects
1 | id classMock = OCMClassMock([SomeClass class]); |
It is possible to stub class and instance methods that conceptually create objects. OCMock automatically adjusts the reference count of the returned object when stubbing methods that have a name that begins with alloc, new, copy, or mutableCopy.
1 | id classMock = OCMClassMock([SomeClass class]); |
It possible, although not advisable, to stub out new for a class. If you find yourself doing this a lot, please consider the dependency injection pattern.
IMPORTANT: It is not possible to stub the init method, because that is implemented by the mock itself.
Instance-based method swizzling
In a nutshell, Method Swizzling describes the replacement of a method implementation with a different implementation at runtime. Using partial mocks and the andCall action OCMock allows such replacements on a per-instance basis.
1 | id partialMock = OCMPartialMock(anObject); |
After these two lines, when someMethod is sent to anObject the implementation of that method is not invoked. Instead, differentMethod is called on differentObject. Other instances of the same class are not affected; for these the original implementation of someMethod is still invoked. The methods can have different names but their signatures should be the same.
Limitations
Only one mock at a time can stub class methods on a given class
1 | // don't do this |
As mentioned above, if the mock object that added a stubbed class method is not deallocated then the stubbed method will persist, even across tests. If multiple mock objects manipulate the same class at the same time the behaviour is undefined.
Setting up expect after stub on the same method does not work
1 | id mock = OCMStrictClassMock([SomeClass class]); |
The code above first sets up a stub for someMethod and afterwards an expectation for the same method. Due to the way mock objects are currently implemented any calls to someMethod are handled by the stub. This means that even if the method is called the verify fails. It is possible to avoid this problem by adding andReturn to the expect statement. You can also set up a stub after the expect.
Partial mocks cannot be created for certain special classes
1 | id partialMockForString = OCMPartialMock(@"Foo"); // will throw an exception |
It is not possible to create partial mocks for instances of toll-free bridged class, e.g. NSString, or for objects represented with tagged pointers, e.g. NSDate on some architectures. The mock object will throw a descriptive exception should you try to do this.
Certain methods cannot be stubbed or verified
1 | id partialMockForString = OCMPartialMock(anObject); |
It is not possible to mock a number of core runtime methods. This includes init, class, methodSignatureForSelector:, forwardInvocation:, respondsToSelector:, and several others.
Note that class is automatically stubbed to return the original class of the object, and not the dynamic subclass used by the partial mock.
Class methods on NSString and NSArray cannot be stubbed or verified
1 | id stringMock = OCMClassMock([NSString class]); |
It is not possible to stub or verify class methods on NSString and NSArray. Trying to do so has no effect.
Methods on NSObject cannot be verified
1 | id mock = OCMClassMock([NSObject class]); |
It is not possible use verify-after-running with methods implemented in NSObject or a category on it. In some cases it is possible to stub the method and then verify it. It is possible to use verify-after-running when the method is overriden in a subclass.
Private methods in core Apple classes cannot be verified
1 | UIWindow *window = /* get window somehow */ |
It is not possible use verify-after-running with private methods in core Apple classes. Specifically, all methods with an underscore prefix and/or suffix in a class with either NS or UI as prefix. In some cases it is possible to stub the method and then verify it.
Verify-after-running cannot use a delay
It is currently not possible to verify a method with a delay. This is currently only possible using the expect-run-verify approach described below in strict mocks and expectations.
Using multiple threads in tests
OCMock is not fully thread-safe. Up to version 3.2.x OCMock was not thread-aware at all. Any combination of operations on a mock object from multiple threads was likely to cause issues and make the test fail.
As of OCMock 3.3 it is still necessary to invoke all setup and verification operations from a single thread, preferrably the main thread of the test runner. It is possible, though, to use the mock object from multiple threads. The mock object can even be used from a different thread while its setup continues in the main thread.